package yw

import (
	"LogisticsPort/model"
	"LogisticsPort/sql"
	"errors"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"strconv"
)

func processing(r *gin.RouterGroup) {
	processing := r.Group("/processing")
	{
		processing.POST(sql.RequestAdd, processingAdd)
		processing.POST(sql.RequestUpdate, processingUpdate)
		processing.GET(sql.RequestDelete, processingDelete)
		processing.GET(sql.RequestData, processingData)
		processing.GET(sql.RequestList, processingList)
	}
}
func processingAdd(c *gin.Context) {
	sql.HttpHandle(sql.ADD, c, func(db *gorm.DB) (*gorm.DB, interface{}) {
		var bean model.Processing
		if err := c.BindJSON(&bean); err != nil {
			db.Error = err
			return db, nil
		}
		if err := db.Transaction(func(tx *gorm.DB) error {
			var material model.Material
			//根据原料id对原来库存进行修改
			for _, processingMaterial := range bean.YwProcessingMaterial {
				if err := tx.
					Table("yw_material").
					Where("yw_material.id = ?", processingMaterial.MaterialId).
					Find(&material).Error; err != nil {
					return err
				}
				number := material.InventoryNumber - processingMaterial.MaterialNumber
				weight := material.InventoryWeight - processingMaterial.MaterialWeight
				if number >= 0 && weight >= 0 {
					if err := tx.Table("yw_material").
						Where("yw_material.id = ?", processingMaterial.MaterialId).
						Updates(map[string]interface{}{
							"inventory_number": number,
							"inventory_weight": weight,
						}).Error; err != nil {
						return err
					}
				} else {
					return errors.New(material.MaterialName + "库存不足")
				}
			}

			//根据成品id对成品库存进行修改
			for _, product := range bean.YwProcessingProduct {
				if err := tx.Table("yw_product").
					Where("yw_product.id = ?", product.ProductId).
					Updates(map[string]interface{}{
						"inventory_weight": gorm.Expr("inventory_weight + ?", product.ProductWeight),
						"inventory_number": gorm.Expr("inventory_number + ?", product.ProductNumber),
					}).Error; err != nil {
					return err
				}
			}
			if err := tx.Table("yw_processing").Create(&bean).Error; err != nil {
				return err
			}
			return nil
		}); err != nil {
			db.Error = err
			return db, nil
		}
		return db, bean
	})
}

func processingUpdate(c *gin.Context) {
	sql.HttpHandle(sql.ADD, c, func(db *gorm.DB) (*gorm.DB, interface{}) {
		var bean model.Processing
		if err := c.BindJSON(&bean); err != nil {
			db.Error = err
			return db, nil
		}
		if err := db.Transaction(func(tx *gorm.DB) error {
			//根据原料id对原来库存进行修改
			var material model.Material
			for _, processingMaterial := range bean.YwProcessingMaterial {
				if err := tx.
					Table("yw_material").
					Where("yw_material.id = ?", processingMaterial.MaterialId).
					Find(&material).Error; err != nil {
					return err
				}

				number := material.InventoryNumber - processingMaterial.MaterialNumber
				weight := material.InventoryWeight - processingMaterial.MaterialWeight
				if number >= 0 && weight >= 0 {
					if err := tx.Table("yw_material").
						Where("yw_material.id = ?", processingMaterial.MaterialId).
						Updates(map[string]interface{}{
							"inventory_number": number,
							"inventory_weight": weight,
						}).Error; err != nil {
						return err
					}
				} else {
					return errors.New(material.MaterialName + "库存不足")
				}
			}

			//根据成品id对成品库存进行修改
			for _, processingProduct := range bean.YwProcessingProduct {
				var oldProcessingProduct model.YwProcessingProduct
				tx.Table("yw_processing_product").
					Where("processing_id = ?", processingProduct.ProcessingId).
					Find(&oldProcessingProduct)
				var weight = oldProcessingProduct.ProductWeight - processingProduct.ProductWeight
				var number = oldProcessingProduct.ProductNumber - processingProduct.ProductNumber

				if err := tx.Table("yw_product").
					Where("yw_product.id = ?", processingProduct.ProductId).
					Updates(map[string]interface{}{
						"inventory_weight": gorm.Expr("inventory_weight - ?", weight),
						"inventory_number": gorm.Expr("inventory_number - ?", number),
					}).Error; err != nil {
					return err
				}
			}
			if err := tx.Table("yw_processing").
				Session(&gorm.Session{FullSaveAssociations: true}).
				Updates(&bean).Error; err != nil {
				return err
			}
			return nil
		}); err != nil {
			db.Error = errors.New(sql.ErrorService)
			return db, nil
		}
		return db, bean
	})
}

func processingData(c *gin.Context) {
	sql.HttpDataTable(c, "yw_processing", &model.Processing{}, func(db *gorm.DB) *gorm.DB {
		var id = c.Query("id")
		db = db.
			Debug().
			Where("id = ?", id).
			Preload("YwProcessingMaterial").
			Preload("YwProcessingProduct")
		return db
	})
}

func processingList(c *gin.Context) {
	sql.HttpListTable(c, "yw_processing", &[]model.Processing{}, func(db *gorm.DB) *gorm.DB {
		db = db.Preload("YwProcessingMaterial").
			Preload("YwProcessingProduct").
			Order("date Desc")
		return db
	})
	/*sql.HttpList(c, []model.Processing, func(db *gorm.DB) (*gorm.DB, interface{}) {
		var list []model.Processing
		db = db.Preload("YwProcessMaterial").
			Preload("YwProcessProduct").
			Order("date Desc").
			Find(&list)
		return db, list
	})*/
}

func processingDelete(c *gin.Context) {
	sql.HttpHandle(sql.DELETE, c, func(db *gorm.DB) (*gorm.DB, interface{}) {
		idStr := c.Query("id")
		id, _ := strconv.Atoi(idStr)
		if err := db.Transaction(func(tx *gorm.DB) error {
			var processingBean model.Processing
			if err := tx.Table("yw_processing").
				Preload("YwProcessingMaterial").
				Preload("YwProcessingProduct").
				Where("id = ?", id).Find(&processingBean).Error; err != nil {
				return err
			}

			//原料库存修改yw_material
			for _, processingMaterial := range processingBean.YwProcessingMaterial {
				if err := tx.Table("yw_material").
					Where("yw_material.id = ?", processingMaterial.MaterialId).
					Updates(map[string]interface{}{
						"inventory_weight": gorm.Expr("inventory_weight + ?", processingMaterial.MaterialWeight),
						"inventory_number": gorm.Expr("inventory_number + ?", processingMaterial.MaterialNumber),
					}).Error; err != nil {
					return err
				}
			}

			//成品库存修改yw_product
			for _, processingProduct := range processingBean.YwProcessingProduct {
				var ywProduct model.FinishedProduct
				if err := tx.
					Table("yw_product").
					Where("yw_product.id = ?", processingProduct.ProductId).
					Find(&ywProduct).Error; err != nil {
					return err
				}
				number := ywProduct.InventoryNumber - processingProduct.ProductNumber
				weight := ywProduct.InventoryWeight - processingProduct.ProductWeight
				if number > 0 && weight > 0 {
					if err := tx.Table("yw_product").
						Where("yw_product.id = ?", processingProduct.ProcessingId).
						Updates(map[string]interface{}{
							"inventory_weight": gorm.Expr("inventory_weight - ?", processingProduct.ProductWeight),
							"inventory_number": gorm.Expr("inventory_number - ?", processingProduct.ProductNumber),
						}).Error; err != nil {
						return err
					}
				} else {
					return errors.New(ywProduct.ProductBrand + ywProduct.ProductName + "成品库存不足，不能删除")
				}
			}

			//关联删除yw_processing、yw_processing_material、yw_processing_product
			if err := tx.Select(clause.Associations).Delete(&model.Processing{
				Model: gorm.Model{ID: uint(id)},
			}).Error; err != nil {
				return err
			}
			return nil
		}); err != nil {
			db.Error = errors.New(sql.ErrorService)
			return db, nil
		}

		db = db.Select(clause.Associations).Delete(&model.Processing{
			Model: gorm.Model{ID: uint(id)},
		})
		return db, nil
	})
}
